package com.east.sng.utils;

import org.apache.ibatis.cache.Cache;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @author east
 * @date: 2021/1/4
 * @Description: Mybatis customer cache implementation
 */
public class RedisCache implements Cache {
    private static final Logger logger = LoggerFactory.getLogger(RedisCache.class);

    private static RedisTemplate<String, Object> redisTemplate;

    private final String id;

    /**
     * The {@code ReadWriteLock}.
     */
    private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    @Override
    public ReadWriteLock getReadWriteLock() {
        return this.readWriteLock;
    }

    public static void setRedisTemplate(RedisTemplate redisTemplate) {
        RedisCache.redisTemplate = redisTemplate;
    }

    public RedisCache(final String id) {
        if (id == null) {
            throw new IllegalArgumentException("Cache instances require an ID");
        }
        logger.debug("MybatisRedisCache :id=" + id);
        this.id = id;
    }

    @Override
    public String getId() {
        return this.id;
    }

    @Override
    public void putObject(Object key, Object value) {
        try {
            if (null != value) {
                Object generateKey = generateKey(key);
                logger.debug("=>putObject: key=" + generateKey + "");
                redisTemplate.opsForValue().set(generateKey.toString(), value, 1, TimeUnit.DAYS);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("redis保存数据异常！");
        }
    }

    @Override
    public Object getObject(Object key) {
        try {
            if (null != key) {
                Object generateKey = generateKey(key);
                logger.debug("=>getObject: key=" + generateKey);
                return redisTemplate.opsForValue().get(generateKey);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("redis获取数据异常！");
        }
        return null;
    }

    @Override
    public Object removeObject(Object key) {
        try {
            if (null != key) {
                Object generateKey = generateKey(key);
                logger.debug("=>removeObject: key=" + generateKey);
                return redisTemplate.expire(generateKey.toString(), 1, TimeUnit.DAYS);
            }
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("redis获取数据异常！");
        }
        return null;
    }

    @Override
    public void clear() {
        Long size = redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection redisConnection) throws DataAccessException {
                Long size = redisConnection.dbSize();
                //连接清除数据
                redisConnection.flushDb();
                redisConnection.flushAll();
                return size;
            }
        });
        logger.debug("===>clear: 清除了" + size + "个对象");
    }

    @Override
    public int getSize() {
        Long size = redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection)
                    throws DataAccessException {
                return connection.dbSize();
            }
        });
        return size.intValue();
    }

    /**
     * 生成key
     * @param nativeKey 原生key
     * @return 自定义拼接的key
     */
    public Object generateKey(Object nativeKey) {
        String[] arr = nativeKey.toString().split(":");
        Long str = (Long.parseLong(arr[0]) ^ Long.parseLong(arr[1]));
        String[] packageNames = arr[2].split("\\.");
        String key = packageNames[packageNames.length - 2] + ":" + packageNames[packageNames.length - 1] + ":" + str;
        return key;
    }

}
